package com.flycms.modules.user.api.wechat;

import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import cn.binarywang.wx.miniapp.bean.WxMaUserInfo;
import com.alibaba.fastjson.JSONObject;
import com.flycms.common.constant.UserConstants;
import com.flycms.common.utils.CharUtils;
import com.flycms.common.utils.DateUtils;
import com.flycms.common.utils.ip.IpUtils;
import com.flycms.modules.notify.domain.SmsCode;
import com.flycms.modules.notify.service.IAliyunService;
import com.flycms.modules.notify.service.ISmsCodeService;
import com.flycms.modules.user.domain.User;
import com.flycms.modules.user.domain.UserApp;
import com.flycms.modules.user.domain.UserAppMerge;
import com.flycms.modules.user.domain.dto.UserInfoDTO;
import com.flycms.modules.user.service.IUserAppMergeService;
import com.flycms.modules.user.service.IUserAppService;
import com.flycms.modules.user.service.IUserService;
import com.flycms.modules.user.util.*;
import io.jsonwebtoken.Claims;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import com.flycms.modules.user.util.JwtTokenUtils;
import com.flycms.modules.user.domain.vo.WxLoginVo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.util.StringUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * 鉴权服务
 */
@Api("用户注册登录")
@RestController
@RequestMapping("/wx/auth")
@Validated
public class WxAuthController {
	private static final Logger logger = LoggerFactory.getLogger(WxAuthController.class);

	@Autowired
	private IUserService userService;

	@Autowired
	private WxMaService wxService;

	@Autowired
	private IUserAppService userAppService;

	@Autowired
	private IUserAppMergeService userAppMergeService;

	@Autowired
	private IAliyunService aliyunServiceImpl;

	@Autowired
	private ISmsCodeService smsCodeService;

	@Autowired
	private JwtTokenUtils jwtTokenUtils;

	/*@Autowired
	private NotifyService notifyService;

	@Autowired
	private CouponAssignService couponAssignService;*/

	/**
	 * 账号登录
	 *
	 * @param body
	 *            请求内容，{ username: xxx, password: xxx }
	 * @param request
	 *            请求对象
	 * @return 登录结果
	 */
/*	@PostMapping("login")
	public Object login(@RequestBody String body, HttpServletRequest request) {
		logger.info("【请求开始】账户登录,请求参数,body:{}", body);

		String username = JacksonUtil.parseString(body, "username");
		String password = JacksonUtil.parseString(body, "password");
		if (username == null || password == null) {
			return ResponseUtil.badArgument();
		}

		List<DtsUser> userList = userService.queryByUsername(username);
		DtsUser user = null;
		if (userList.size() > 1) {
			logger.error("账户登录 出现多个同名用户错误,用户名:{},用户数量:{}", username, userList.size());
			return ResponseUtil.serious();
		} else if (userList.size() == 0) {
			logger.error("账户登录 用户尚未存在,用户名:{}", username);
			return ResponseUtil.badArgumentValue();
		} else {
			user = userList.get(0);
		}

		BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
		if (!encoder.matches(password, user.getPassword())) {
			logger.error("账户登录 ,错误密码：{},{}", password, AUTH_INVALID_ACCOUNT.desc());// 错误的密码打印到日志中作为提示也无妨
			return WxResponseUtil.fail(AUTH_INVALID_ACCOUNT);
		}

		// userInfo
		UserInfo userInfo = new UserInfo();
		userInfo.setNickName(username);
		userInfo.setAvatarUrl(user.getAvatar());
		
		try {
			String registerDate = new SimpleDateFormat("yyyy-MM-dd")
					.format(user.getAddTime() == null ? user.getAddTime() : LocalDateTime.now());
			userInfo.setRegisterDate(registerDate);
			userInfo.setStatus(user.getStatus());
			userInfo.setUserLevel(user.getUserLevel());// 用户层级
			userInfo.setUserLevelDesc(UserTypeEnum.getInstance(user.getUserLevel()).getDesc());// 用户层级描述
		} catch (Exception e) {
			logger.error("账户登录：设置用户指定信息出错："+e.getMessage());
			e.printStackTrace();
		}

		// token
		UserToken userToken = null;
		try {
			userToken = UserTokenManager.generateToken(user.getId());
		} catch (Exception e) {
			logger.error("账户登录失败,生成token失败：{}", user.getId());
			e.printStackTrace();
			return ResponseUtil.fail();
		}

		Map<Object, Object> result = new HashMap<Object, Object>();
		result.put("token", userToken.getToken());
		result.put("tokenExpire", userToken.getExpireTime().toString());
		result.put("userInfo", userInfo);

		logger.info("【请求结束】账户登录,响应结果:{}", JSONObject.toJSONString(result));
		return ResponseUtil.ok(result);
	}*/

	/**
	 * 微信登录
	 *
	 *            请求内容，{ code: xxx, userInfo: xxx }
	 * @param request
	 *            请求对象
	 * @return 登录结果
	 */
	@ApiOperation("用户登录")
	@PostMapping("login_by_weixin")
	public Object loginByWeixin(@Validated @RequestBody WxLoginVo login, HttpServletRequest request) {

		if (StringUtils.isEmpty(login.getIv()) || StringUtils.isEmpty(login.getEncryptedData()) || StringUtils.isEmpty(login.getWxCode())) {
			return ResponseUtil.fail(401,"未正确获取微信客户端信息");
		}
		WxMaJscode2SessionResult wxResult = null;
		WxMaUserInfo userInfo = null;
		try {
			wxResult = this.wxService.getUserService().getSessionInfo(login.getWxCode());
			userInfo = this.wxService.getUserService().getUserInfo(wxResult.getSessionKey(),login.getEncryptedData(),login.getIv());
			System.out.println(JSONObject.toJSONString(userInfo));
		} catch (Exception e) {
			logger.error("请求账号注册出错:{}", WxResponseCode.AUTH_OPENID_UNACCESS.desc());
			//e.printStackTrace();
			return WxResponseUtil.fail(WxResponseCode.AUTH_OPENID_UNACCESS);
		}

		UserApp app = new UserApp();
		app.setOpenId(wxResult.getOpenid());
		app.setNickName(userInfo.getNickName());
		app.setAvatarUrl(userInfo.getAvatarUrl());
		app.setPlatform("微信");
		app.setCountry(userInfo.getCountry());
		app.setProvince(userInfo.getProvince());
		app.setCity(userInfo.getCity());
		app.setGender(Integer.parseInt(userInfo.getGender()));
		app.setLanguage(userInfo.getLanguage());

		if (!StringUtils.isEmpty(wxResult.getUnionid())) { //判断是否能获取到Unionid
			UserApp unionUser=userAppService.selectUserAppByUnionId(wxResult.getUnionid());
			if(unionUser != null){
				app.setId(unionUser.getId());
			}else{
				app.setUnionId(wxResult.getUnionid());
				userAppService.insertUserApp(app);
			}
		}else{//如果不是则检查是否是OpenId用户
			UserApp openIdUser=userAppService.selectUserAppByOpenId(wxResult.getOpenid());
			if(openIdUser != null){
				app.setId(openIdUser.getId());
			}else{
				userAppService.insertUserApp(app);
			}
		}

		Map<Object, Object> returnMap = new HashMap<Object, Object>();
		returnMap.put("token", jwtTokenUtils.generateToken(app.getId()));
		returnMap.put("userInfo", app);

		logger.info("【请求结束】账号注册,响应结果:{}", JSONObject.toJSONString(returnMap));
		return ResponseUtil.ok(returnMap);
	}

	/**
	 * 请求验证码
	 *
	 * @param body
	 *            手机号码{mobile}
	 * @return
	 */
	@PostMapping("regCaptcha")
	public Object registerCaptcha(@RequestBody String body) {
		logger.info("【请求开始】请求验证码,请求参数，body:{}", body);

		String phoneNumber = JacksonUtil.parseString(body, "mobile");
		if (StringUtils.isEmpty(phoneNumber)) {
			return ResponseUtil.badArgument();
		}
		if (!RegexUtil.isMobileExact(phoneNumber)) {
			return ResponseUtil.badArgumentValue();
		}
		String code = CharUtils.getRandomNum(6);
		SmsCode smsCode=new SmsCode();
		smsCode.setUserName(phoneNumber);
		smsCode.setTemplateId(317765676100235265l);
		smsCode.setCodeType(1);
		smsCode.setCode(code);
		boolean successful = aliyunServiceImpl.getSendSms(smsCode);
		/*if (!successful) {
			//logger.error("请求验证码出错:{}", WxResponseCode.AUTH_CAPTCHA_FREQUENCY.desc());
			return WxResponseUtil.fail(WxResponseCode.AUTH_CAPTCHA_FREQUENCY);
		}*/

		logger.info("【请求结束】请求验证码成功");
		return ResponseUtil.ok();
	}

	/**
	 * 账号注册
	 *
	 *            请求内容 { username: xxx, password: xxx, mobile: xxx code: xxx }
	 *            其中code是手机验证码，目前还不支持手机短信验证码
	 * @param request
	 *            请求对象
	 * @return 登录结果 成功则 { errno: 0, errmsg: '成功', data: { token: xxx, tokenExpire:
	 *         xxx, userInfo: xxx } } 失败则 { errno: XXX, errmsg: XXX }
	 */
	@RequestMapping(value = "register")
	public Object register(@RequestBody WxLoginVo login, HttpServletRequest request) {
		if (StringUtils.isEmpty(login.getMobile()) || StringUtils.isEmpty(login.getPassword()) || StringUtils.isEmpty(login.getCode())) {
			return ResponseUtil.badArgument();
		}
		if (StringUtils.isEmpty(login.getWxCode())) {
			return ResponseUtil.fail(401,"请使用微信客户端登录");
		}

		if (!RegexUtil.isMobileExact(login.getMobile())) {
			logger.error("请求账号注册出错:{}", WxResponseCode.AUTH_INVALID_MOBILE.desc());
			return WxResponseUtil.fail(WxResponseCode.AUTH_INVALID_MOBILE);
		}
		User loginUser = new User();
		loginUser.setMobile(login.getMobile());
		if (UserConstants.NOT_UNIQUE.equals(userService.checkUserMobileUnique(loginUser)))
		{
			//手机号已存在
			return WxResponseUtil.fail(WxResponseCode.AUTH_MOBILE_REGISTERED);
		}
		// 判断验证码是否正确
		if (smsCodeService.checkSmsCodeCode(login.getMobile(), 1,login.getCode())) {
			//验证通过后修改本条记录为已验证
			smsCodeService.updateSmsCodeByStatus(0,login.getMobile(),login.getCode());
		}else {
			return WxResponseUtil.fail(WxResponseCode.AUTH_CAPTCHA_FREQUENCY);
		}

		WxMaJscode2SessionResult wxResult = null;
		WxMaUserInfo userInfo = null;
		try {
			wxResult = this.wxService.getUserService().getSessionInfo(login.getWxCode());
			userInfo = this.wxService.getUserService().getUserInfo(wxResult.getSessionKey(),login.getEncryptedData(),login.getIv());
			System.out.println(JSONObject.toJSONString(userInfo));
		} catch (Exception e) {
			logger.error("请求账号注册出错:{}", WxResponseCode.AUTH_OPENID_UNACCESS.desc());
			//e.printStackTrace();
			return WxResponseUtil.fail(WxResponseCode.AUTH_OPENID_UNACCESS);
		}
		//System.out.println("=========openId========="+wxResult.getOpenid());
		logger.info("【请求开始】微信登录,请求参数,wxResult:{}", JSONObject.toJSONString(wxResult));

		UserApp app = new UserApp();
		app.setOpenId(wxResult.getOpenid());
		app.setNickName(userInfo.getNickName());
		app.setAvatarUrl(userInfo.getAvatarUrl());
		app.setPlatform("微信");
		app.setCountry(userInfo.getCountry());
		app.setProvince(userInfo.getProvince());
		app.setCity(userInfo.getCity());
		app.setGender(Integer.parseInt(userInfo.getGender()));
		app.setLanguage(userInfo.getLanguage());

		if (!StringUtils.isEmpty(wxResult.getUnionid())) { //判断是否能获取到Unionid
			UserApp unionUser=userAppService.selectUserAppByUnionId(wxResult.getUnionid());
			if(unionUser != null){
				app.setId(unionUser.getId());
			}else{
				app.setUnionId(wxResult.getUnionid());
				userAppService.insertUserApp(app);
			}
		}else{//如果不是则检查是否是OpenId用户
			UserApp openIdUser=userAppService.selectUserAppByOpenId(wxResult.getOpenid());
			if(openIdUser != null){
				app.setId(openIdUser.getId());
			}else{
				userAppService.insertUserApp(app);
			}
		}

		User user = new User();
		BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
		String encodedPassword = encoder.encode(login.getPassword());
		user.setPassword(encodedPassword);
		user.setMobile(login.getMobile());
		user.setAvatar(userInfo.getAvatarUrl());
		user.setNickname(userInfo.getNickName());
		user.setGender(Integer.parseInt(userInfo.getGender()));
		user.setUserLevel(0);
		user.setStatus(0);
		user.setLastLoginTime(DateUtils.getNowDate());
		user.setLastLoginIp(IpUtils.getIpAddr(request));
		userService.insertUser(user);

		//微信客户端与服务端主账户关联
		UserAppMerge merge=new UserAppMerge();
		merge.setAppId(app.getId());
		merge.setUserId(user.getId());
		if (!UserConstants.NOT_UNIQUE.equals(userAppMergeService.checkUserAppMergeUnique(merge)))
		{
			userAppMergeService.insertUserAppMerge(merge);
		}

		// 给新用户发送注册优惠券
		try {
			//couponAssignService.assignForRegister(user.getId());
		} catch (Exception e) {
			//logger.error("账号注册失败,给新用户发送注册优惠券失败：{}", login.getId());
			e.printStackTrace();
			return ResponseUtil.fail();
		}

		// userInfo
		UserInfoDTO returnUserInfo = new UserInfoDTO();
		returnUserInfo.setNickname(userInfo.getNickName());
		returnUserInfo.setAvatar(userInfo.getAvatarUrl());

		String token = jwtTokenUtils.generateToken(user.getId());
		Claims parseJwt = jwtTokenUtils.getClaimsToken(token);
		Date tokenExpire = parseJwt.getIssuedAt();
		Map<Object, Object> returnMap = new HashMap<Object, Object>();
		returnMap.put("token", token);
		//token到期时间
		returnMap.put("tokenExpire", DateUtils.fomatDateToString(tokenExpire));
		returnMap.put("userInfo", returnUserInfo);

		logger.info("【请求结束】账号注册,响应结果:{}", JSONObject.toJSONString(returnMap));
		return ResponseUtil.ok(returnMap);
	}

	/**
	 * 账号密码重置
	 *
	 * @param body
	 *            请求内容 { password: xxx, mobile: xxx code: xxx }
	 *            其中code是手机验证码，目前还不支持手机短信验证码
	 * @param request
	 *            请求对象
	 * @return 登录结果 成功则 { errno: 0, errmsg: '成功' } 失败则 { errno: XXX, errmsg: XXX }
	 */
	/*@PostMapping("reset")
	public Object reset(@RequestBody String body, HttpServletRequest request) {
		logger.info("【请求开始】账号密码重置,请求参数，body:{}", body);

		String password = JacksonUtil.parseString(body, "password");
		String mobile = JacksonUtil.parseString(body, "mobile");
		String code = JacksonUtil.parseString(body, "code");

		if (mobile == null || code == null || password == null) {
			return ResponseUtil.badArgument();
		}

		// 判断验证码是否正确
		String cacheCode = CaptchaCodeManager.getCachedCaptcha(mobile);
		if (cacheCode == null || cacheCode.isEmpty() || !cacheCode.equals(code)) {
			logger.error("账号密码重置出错:{}", AUTH_CAPTCHA_UNMATCH.desc());
			return WxResponseUtil.fail(AUTH_CAPTCHA_UNMATCH);
		}

		List<DtsUser> userList = userService.queryByMobile(mobile);

		DtsUser user = null;
		if (userList.size() > 1) {
			logger.error("账号密码重置出错,账户不唯一,查询手机号:{}", mobile);
			return ResponseUtil.serious();
		} else if (userList.size() == 0) {
			logger.error("账号密码重置出错,账户不存在,查询手机号:{},{}", mobile, AUTH_MOBILE_UNREGISTERED.desc());
			return WxResponseUtil.fail(AUTH_MOBILE_UNREGISTERED);
		} else {
			user = userList.get(0);
		}

		BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
		String encodedPassword = encoder.encode(password);
		user.setPassword(encodedPassword);

		if (userService.updateById(user) == 0) {
			logger.error("账号密码重置更新用户信息出错,id：{}", user.getId());
			return ResponseUtil.updatedDataFailed();
		}

		logger.info("【请求结束】账号密码重置成功!");
		return ResponseUtil.ok();
	}
*/
	/**
	 * 绑定手机号码
	 * 
	 * @param userId
	 * @param body
	 * @return
	 */
	/*@PostMapping("bindPhone")
	public Object bindPhone(@LoginUser Integer userId, @RequestBody String body) {
		logger.info("【请求开始】绑定手机号码,请求参数，body:{}", body);

		String sessionKey = UserTokenManager.getSessionKey(userId);
		String encryptedData = JacksonUtil.parseString(body, "encryptedData");
		String iv = JacksonUtil.parseString(body, "iv");
		WxMaPhoneNumberInfo phoneNumberInfo = null;
		try {
			phoneNumberInfo = this.wxService.getUserService().getPhoneNoInfo(sessionKey, encryptedData, iv);
		} catch (Exception e) {
			logger.error("绑定手机号码失败,获取微信绑定的手机号码出错：{}", body);
			e.printStackTrace();
			return ResponseUtil.fail();
		}
		String phone = phoneNumberInfo.getPhoneNumber();
		DtsUser user = userService.findById(userId);
		user.setMobile(phone);
		if (userService.updateById(user) == 0) {
			logger.error("绑定手机号码,更新用户信息出错,id：{}", user.getId());
			return ResponseUtil.updatedDataFailed();
		}
		Map<Object, Object> data = new HashMap<Object, Object>();
		data.put("phone", phone);

		logger.info("【请求结束】绑定手机号码,响应结果：{}", JSONObject.toJSONString(data));
		return ResponseUtil.ok(data);
	}*/

	/**
	 * 注销登录
	 * 
	 * @param userId
	 * @return
	 */
	/*@PostMapping("logout")
	public Object logout(@LoginUser Integer userId) {
		logger.info("【请求开始】注销登录,请求参数，userId:{}", userId);
		if (userId == null) {
			return ResponseUtil.unlogin();
		}
		try {
			UserTokenManager.removeToken(userId);
		} catch (Exception e) {
			logger.error("注销登录出错：userId:{}", userId);
			e.printStackTrace();
			return ResponseUtil.fail();
		}

		logger.info("【请求结束】注销登录成功!");
		return ResponseUtil.ok();
	}*/
}
